﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;

namespace RazorTemplateEngine
{
    public class TemplatePageExecutor
    {
        Assembly targetAssembly;
        public TemplatePageExecutor(Assembly assemby)
        {
            targetAssembly = assemby;
        }

        public string Execute(ExecuteContext executeContext)
        {
            object targetInstance = targetAssembly.CreateInstance(TemplatePageRazorHost.NamespanceConst + "." + TemplatePageRazorHost.ClassNameConst);
            Type page = targetAssembly.GetType(TemplatePageRazorHost.NamespanceConst + "." + TemplatePageRazorHost.ClassNameConst);

            SetTemplateData(page, targetInstance, executeContext);
            SetChildBody(page, targetInstance, executeContext);
           
            //execute
            page.InvokeMember(
                "Execute",
                BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
                null,
                targetInstance,
                null);
            //get template result
            string  _currentBody = page.GetProperty(
                "ParseResult",
                BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance).GetValue(targetInstance,null).ToString();
            //get layout
            object _layout = page.GetProperty(
                "Layout",
                BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance
                ).GetValue(targetInstance,null);

            //if no layout
            if (_layout == null || string.IsNullOrEmpty(_layout.ToString()))
                return _currentBody;
            //set next's child = this body
            executeContext.ChildBody = _currentBody;

            //if not cache , build it!
            DynamicAssemblyCache asmCache = new DynamicAssemblyCache(_layout.ToString(), executeContext);
            Assembly compiledAssembly = asmCache.GetAssemblyFromRazor();
            TemplatePageExecutor executor = new TemplatePageExecutor(compiledAssembly);
            return executor.Execute(executeContext);
        }

        private void SetTemplateData(Type pageType, object Target, ExecuteContext context)
        {
            //set templateData
            PropertyInfo templateDataProperty = pageType.GetProperty(
                "TemplateData",
                BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance);
            templateDataProperty.SetValue(Target, context.tempData.TempData, null);
        }

        private void SetChildBody(Type pageType, object Target, ExecuteContext context)
        {
            //set childbody
            PropertyInfo childBody = pageType.GetProperty(
                "ChildBody",
                BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance);
            childBody.SetValue(Target, context.ChildBody, null);
        }
    }
}
